package third_assignment;

import java.util.Vector;

//import third_assignment.Consts_3rd.*;
import first_assignment.*;
import second_assignment.*;
//import second_assignment.Consts_2nd.*;
import first_assignment.Consts_1st.*;

public class StaticSimulator {
	MovieCollection movieCollectionLib;
	MovieCollection movieCollectionRecorded;
	MovieCollection movieCollectionRecent;
	
	//private int[] copiesLibrary;
	private int[] copiesRecorded;
	private int[] copiesRecent;
	
	Manager manager;
	
	int RRDeleteIndex = 1;
	public int currentDay = 1;

	public StaticSimulator() {

        Vector<Integer> moviesAmount = new Vector<Integer>(3);
        Vector<Double> probability = new Vector<Double>(3);
        Vector<Integer> popularityDistrib = new Vector<Integer>(3);
        
        moviesAmount.add(0, Consts_2nd.M_Library);
        moviesAmount.add(1, Consts_2nd.M_Recorded);
        moviesAmount.add(2, Consts_2nd.M_RecentlyBroadcast);

        probability.add(0, Consts_2nd.p1);
        probability.add(1, Consts_2nd.p2);
        probability.add(2, Consts_2nd.p3);

        popularityDistrib.add(0, Consts_2nd.a1);
        popularityDistrib.add(1, Consts_2nd.a2);
        popularityDistrib.add(2, Consts_2nd.a3);

        manager = new Manager(probability, moviesAmount, popularityDistrib);

		movieCollectionLib = new MovieCollection(manager.getLibraryArray(), manager.getLibraryDistributionClass(),
				Consts_3rd.Library_NewMovieFactor);
		movieCollectionRecorded = new MovieCollection(manager.getRecordedArray(), manager.getRecordedDistributionClass(),
				Consts_3rd.Recorded_NewMovieFactor);
		movieCollectionRecent = new MovieCollection(manager.getRecentArray(), manager.getRecentlyBroadcastDistributionClass(),
				Consts_3rd.Recently_NewMovieFactor);
		
		//copiesLibrary = manager.getLibraryCopiesArray();
    	copiesRecorded = manager.getRecordedCopiesArray();
    	copiesRecent = manager.getRecentCopiesArray();
	}
    // IMPORTANT : use the new movie for F (cluster array updated)
    public void DeleteMovieCopies(Movie movie, int numOfCopiesToDelete)
    {
    	int copiesToRemove = numOfCopiesToDelete, copies;
    	int counter = 0;
    	while (copiesToRemove > 0){
            if ((Consts_2nd.NumberOfNonRootClusters + 1) == counter++) {
                System.out.println("ERROR: still " + copiesToRemove + " copies of the movie '" + movie.movieName + "'.");
                System.out.print("ERROR: movies_2_delete: " + numOfCopiesToDelete + ", copies in the system: ( ");
                for (int i=0; i<Consts_2nd.NumberOfNonRootClusters + 1; ++i) {
                    System.out.print("<"+i+","+manager.clusters[i].CountCopies(movie.movieName)+"> ");
                }
                System.out.println(")");
                return;//break;
            }
    		// RR on clusters
    		copies = manager.clusters[RRDeleteIndex].CountCopies(movie.movieName);
    		if (copies > 0){
    			if (RRDeleteIndex == 0 && copies == 1 && movie.copies != numOfCopiesToDelete) {
        			RRDeleteIndex = (RRDeleteIndex + 1) % (Consts_2nd.NumberOfNonRootClusters + 1);
    				continue;
    			}
    			if (manager.clusters[RRDeleteIndex].DeleteMovie(movie.movieName)) {
    			    --copiesToRemove;
    			    counter = 0;
    			}
    			else {
    			    System.out.println("ERROR: could not delete movie from cluster " + RRDeleteIndex +
    			            " which contains " + copies + " copies of the movie.");
    			}
    		}
			RRDeleteIndex = (RRDeleteIndex + 1) % (Consts_2nd.NumberOfNonRootClusters + 1);
    	}
    	movie.copies -= numOfCopiesToDelete;
    }

    public int EndOfDay(int day){
        int cost = 0;
		Vector<Movie> deleteLibrary = movieCollectionLib.NewDay(
		        manager.CreateNewSetOfMovies(movieCollectionLib.numOfNewMovies, "Library_Day-" + (day + 1), 0));
    	Vector<Movie> deleteRecorded = movieCollectionRecorded.NewDay(
    	        manager.CreateNewSetOfMovies(movieCollectionRecorded.numOfNewMovies, "Recorded_Day-" + (day + 1), 1));
    	Vector<Movie> deleteRecent = movieCollectionRecent.NewDay(
    	        manager.CreateNewSetOfMovies(movieCollectionRecent.numOfNewMovies, "RecentlyBroadcast_Day-" + (day + 1), 2));
    	// Delete Library Copies
    	for (int i = 0; null != deleteLibrary && i < deleteLibrary.size(); ++i){
    	    cost += deleteLibrary.get(i).copies;
    		DeleteMovieCopies(deleteLibrary.get(i), deleteLibrary.get(i).copies);
    	}
    	// Delete Recorded Copies
    	for (int i = 0; null != deleteRecorded && i < deleteRecorded.size(); ++i){
    	    cost += deleteRecorded.get(i).copies;
    		DeleteMovieCopies(deleteRecorded.get(i), deleteRecorded.get(i).copies);
    	}
    	// Delete Recently Broadcast Copies
    	for (int i = 0; null != deleteRecent && i < deleteRecent.size(); ++i){
    	    cost += deleteRecent.get(i).copies;
    		DeleteMovieCopies(deleteRecent.get(i), deleteRecent.get(i).copies);
    	}

    	//manager.PrintStats("(DEL )");
    	Vector<Movie> F_Recorded = movieCollectionRecorded.getMovieNameList();
    	Vector<Movie> F_Recent = movieCollectionRecent.getMovieNameList();
    	
    	// Reduce number of copies
    	int currCopies;
		int destCopies;

    	for (int i = 0; i < Consts_2nd.M_Recorded; ++i){
    		Movie updatedMovie = F_Recorded.get(i);
    		currCopies = updatedMovie.copies;
    		destCopies = copiesRecorded[i];
    		if (currCopies > destCopies) {
    			DeleteMovieCopies(updatedMovie, currCopies - destCopies);
    			cost += (currCopies - destCopies);
    		}
    		else if (currCopies != 0 && currCopies < destCopies) {
    			updatedMovie.copies = destCopies - currCopies + 1;
    			manager.AddNewMovie(updatedMovie);
    			cost += (destCopies - currCopies + 1);
    			updatedMovie.copies = destCopies;
    		}
    	}
    	for (int i = 0; i < Consts_2nd.M_RecentlyBroadcast; ++i){
    		Movie updatedMovie = F_Recent.get(i);
    		currCopies = updatedMovie.copies;
    		destCopies = copiesRecent[i];
    		if (currCopies > destCopies) {
    			DeleteMovieCopies(updatedMovie, currCopies - destCopies);
    			cost += (currCopies - destCopies);
    		}
    		else if (currCopies != 0 && currCopies < destCopies) {
    			updatedMovie.copies = destCopies - currCopies + 1;
    			manager.AddNewMovie(updatedMovie);
    			cost += (destCopies - currCopies + 1);
    			updatedMovie.copies = destCopies;
    		}
    	}

    	//manager.PrintStats("(REDC)");

    	int index;
    	
    	// Add new recorded movies - first copy to root
    	index = F_Recorded.size()-1;
    	int newRecordedCopies = movieCollectionRecorded.numOfNewMovies;  
    	while (index >= F_Recorded.size() - newRecordedCopies){
    		if (F_Recorded.get(index).copies == 0 && manager.AddCopyToRoot(F_Recorded.get(index)) >= 0) {
    			F_Recorded.get(index).copies++;
   			}
    		else {
    			System.out.println("ERROR: failed to add 1st copy of '" + 
    					F_Recorded.get(index).movieName + "' to the root cluster");
    		}
   			--index;
    	}
    	
    	// Add new recently broadcast movies - first copy to root
    	index = F_Recent.size()-1;
    	int newRecentCopies = movieCollectionRecent.numOfNewMovies;
    	while (index >= F_Recent.size() - newRecentCopies){
    		if (F_Recent.get(index).copies == 0 && manager.AddCopyToRoot(F_Recent.get(index)) >= 0) {
    			F_Recent.get(index).copies++;
   			}
    		else {
    			System.out.println("ERROR: failed to add 1st copy of '" + 
    					F_Recent.get(index).movieName + "' to the root cluster");
    		}
   			--index;
    	}

    	//manager.PrintStats("(ROOT)");
		//System.out.println("(ROOT) new <RECENT> copies: " + newRecentCopies + ", new <RECORDED> copies: " + newRecordedCopies);

		// Add the rest of the copies - recorded
    	index = F_Recorded.size()-1;
    	while (index >= F_Recorded.size() - newRecordedCopies){
    		if (F_Recorded.get(index).copies <= 1){
    			Movie newMovie = F_Recorded.get(index);
    			newMovie.copies = copiesRecorded[index];
    			manager.AddNewMovie(newMovie);
    			cost += newMovie.copies;
    		}
    		--index;
    	}

    	// Add the rest of the copies - recent
    	index = F_Recent.size()-1;
    	while (index >= F_Recent.size() - newRecentCopies){
    		if (F_Recent.get(index).copies <= 1){
    			Movie newMovie = F_Recent.get(index);
    			newMovie.copies = copiesRecent[index];
    			manager.AddNewMovie(newMovie);
    			cost += newMovie.copies;
    		}
    		--index;
    	}
    	//manager.PrintStats("(EOD )");
    	//System.out.println("********************************************************************");
    	return cost;
    }

	public Manager getManager() {
		return manager;
	}
    public MovieCollection getMovieCollectionLibrary() {
        return movieCollectionLib;
    }
    public MovieCollection getMovieCollectionRecorded() {
        return movieCollectionRecorded;
    }
    public MovieCollection getMovieCollectionRecent() {
        return movieCollectionRecent;
    }
  
}
